package gptma.fo.listener;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;

/**
 * @see http 
 *      ://ocpsoft.com/java/persist-and-pass-facesmessages-over-page-redirects/
 * @author xcl
 */
public class FacesMessagePhaseListener implements PhaseListener {

	private static final long serialVersionUID = -6201869382106150592L;

	private static final String SESSION_TOKEN = "MULTI_PAGE_MESSAGES_SUPPORT";

	@Override
	public PhaseId getPhaseId() {
		return PhaseId.ANY_PHASE;
	}

	@Override
	public void beforePhase(PhaseEvent event) {
		FacesContext context = event.getFacesContext();
		saveMessages(context);

		if (PhaseId.RENDER_RESPONSE.equals(event.getPhaseId())) {
			if (!context.getResponseComplete()) {
				restoreMessages(context);
			}
		}
	}

	@Override
	public void afterPhase(PhaseEvent event) {
		if (!PhaseId.RENDER_RESPONSE.equals(event.getPhaseId())) {
			FacesContext context = event.getFacesContext();
			saveMessages(context);
		}
	}

	@SuppressWarnings("unchecked")
	private void saveMessages(FacesContext context) {
		List<FacesMessage> messages = new ArrayList<FacesMessage>();
		for (Iterator<FacesMessage> iter = context.getMessages(); iter
				.hasNext();) {
			messages.add(iter.next());
			iter.remove();
		}

		if (!messages.isEmpty()) {
			Map<String, Object> sessionMap = context.getExternalContext()
					.getSessionMap();
			List<FacesMessage> existing = (List<FacesMessage>) sessionMap
					.get(SESSION_TOKEN);

			if (existing == null) {
				existing = new ArrayList<FacesMessage>();
				sessionMap.put(SESSION_TOKEN, existing);
			}

			existing.addAll(messages);
		}
	}

	@SuppressWarnings("unchecked")
	private void restoreMessages(FacesContext context) {
		Map<String, Object> sessionMap = context.getExternalContext()
				.getSessionMap();
		List<FacesMessage> messages = (List<FacesMessage>) sessionMap
				.remove(SESSION_TOKEN);

		if (messages != null) {
			for (FacesMessage facesMessage : messages) {
				context.addMessage(null, facesMessage);
			}
		}
	}

}
